package org.sunrise.game.http.server;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import lombok.Data;
import org.sunrise.game.center.client.ReportClientMessageManager;
import org.sunrise.game.center.message.ReportMessage;
import org.sunrise.game.center.server.NodeManager;
import org.sunrise.game.common.log.LogCore;
import org.sunrise.game.common.message.MessageUtils;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * http 上报客户端 消息管理类
 * 收到master的消息后，进行处理
 */
public class HttpReportMessageManager extends ReportClientMessageManager {
    @Data
    public class RemoteData {
        private long time = 0L;
        private String ip;
        private int id;
        private int port;
    }

    private static final Map<Integer, Map<Integer, RemoteData>> remoteStatus = new ConcurrentHashMap<>();

    public HttpReportMessageManager(String nodeId) {
        super(nodeId);
    }

    @Override
    protected void pulseHandlerOne(Object data) {
        var message = MessageUtils.fromMessage((byte[]) data, ReportMessage.class);
        Map<Integer, RemoteData> map = remoteStatus.computeIfAbsent(message.getType(), k -> new HashMap<>());
        if (message.getType() == NodeManager.NODE_TYPE_EXTERNAL) {
            RemoteData remoteData = map.get(message.getServerId());
            if (remoteData == null) {
                remoteData = new RemoteData();
                remoteData.setId(message.getServerId());
                map.put(message.getServerId(), remoteData);
            }
            remoteData.setIp(message.getIp());
            remoteData.setPort(message.getPort());
            remoteData.setTime(System.currentTimeMillis());
        } else if (message.getType() == NodeManager.NODE_TYPE_GAME) {
            RemoteData remoteData = map.get(message.getServerId());
            if (remoteData == null) {
                remoteData = new RemoteData();
                remoteData.setId(message.getServerId());
                map.put(message.getServerId(), remoteData);
            }
            remoteData.setTime(System.currentTimeMillis());
        }
        LogCore.Client.debug("recv msg, cur NodeId = { {} }, from NodeId = { {} }, messageId = { {} }, data = { {} }", getNodeId(), message.getNodeId(), message.getMessageId(), message);
    }

    public static void check() {
        long currentTimeMillis = System.currentTimeMillis();
        for (Map.Entry<Integer, Map<Integer, RemoteData>> entry : remoteStatus.entrySet()) {
            if (entry.getKey() == NodeManager.NODE_TYPE_EXTERNAL) {
                JSONArray externalAddress = new JSONArray();
                for (Map.Entry<Integer, RemoteData> remoteDataEntry : entry.getValue().entrySet()) {
                    if (remoteDataEntry.getValue().getTime() + NodeManager.INTERVAL * 2L > currentTimeMillis) {
                        JSONObject jsonResponse1 = new JSONObject();
                        jsonResponse1.put("address", remoteDataEntry.getValue().getIp() + ":" + remoteDataEntry.getValue().getPort());
                        jsonResponse1.put("type", "tcp");
                        externalAddress.add(jsonResponse1);

                        JSONObject jsonResponse2 = new JSONObject();
                        jsonResponse2.put("address", remoteDataEntry.getValue().getIp() + ":" + (remoteDataEntry.getValue().getPort() + 1));
                        jsonResponse2.put("type", "websocket");
                        externalAddress.add(jsonResponse2);
                    }
                }
                String response = HttpServer.responses.get("/external_address_list");
                var data = externalAddress.toJSONString();
                if (response == null || !response.equals(data)) {
                    HttpServer.responses.put("/external_address_list", data);
                    LogCore.HttpServer.info("HttpServer UpdateExternalAddressList success, data = {}", data);
                }
            } else if (entry.getKey() == NodeManager.NODE_TYPE_GAME) {
                JSONArray gameIds = new JSONArray();
                for (Map.Entry<Integer, RemoteData> remoteDataEntry : entry.getValue().entrySet()) {
                    if (remoteDataEntry.getValue().getTime() + NodeManager.INTERVAL * 2L > currentTimeMillis) {
                        JSONObject jsonResponse = new JSONObject();
                        jsonResponse.put("server_id", remoteDataEntry.getValue().getId());
                        gameIds.add(jsonResponse);
                    }
                }
                String response = HttpServer.responses.get("/game_id_list");
                var data = gameIds.toJSONString();
                if (response == null || !response.equals(data)) {
                    HttpServer.responses.put("/game_id_list", data);
                    LogCore.HttpServer.info("HttpServer UpdateGameIdList success, data = {}", data);
                }
            }
        }
    }
}
